import numpy as np
import matplotlib.pyplot as plt
from sklearn.neighbors import KNeighborsClassifier
from matplotlib.colors import ListedColormap
plt.rcParams["font.family"] = ["SimHei", "WenQuanYi Micro Hei", "Heiti TC"]
plt.rcParams["axes.unicode_minus"] = False  # 解决负号显示问题
#  生成高斯分布数据集
print("正在生成高斯分布数据集...")
# 生成第一类数据（蓝色，标签0）：均值(1,2)，方差1的高斯分布，100个样本
data_class0 = np.random.multivariate_normal(mean=[1, 2], cov=[[1, 0], [0, 1]], size=100)
# 生成第二类数据（红色，标签1）：均值(4,3)，方差1的高斯分布，100个样本
data_class1 = np.random.multivariate_normal(mean=[4, 3], cov=[[1, 0], [0, 1]], size=100)
# 合并数据并添加标签（0/1）
data = np.vstack([
    np.hstack([data_class0, np.zeros((100, 1))]),  # 第一类加标签0
    np.hstack([data_class1, np.ones((100, 1))])  # 第二类加标签1
])
np.savetxt('gauss.csv', data, delimiter=',')
print("数据集生成完成！共200个样本（两类各100个），已保存为 gauss.csv")

# 分离特征（前两列）和标签（第三列）
x_train = data[:, :2]
y_train = data[:, 2]

# 可视化原始数据集
plt.figure(figsize=(8, 6))
# 绘制两类样本
plt.scatter(x_train[y_train == 0, 0], x_train[y_train == 0, 1], c='blue', marker='o', label='类别0（蓝色）')
plt.scatter(x_train[y_train == 1, 0], x_train[y_train == 1, 1], c='red', marker='x', label='类别1（红色）')
plt.xlabel('特征1（X轴）')
plt.ylabel('特征2（Y轴）')
plt.title('原始高斯分布数据集可视化')
plt.legend()
plt.grid(alpha=0.3)
plt.show()

# 构造测试网格（用于展示分类边界
step = 0.02  # 网格步长（越小边界越平滑）
# 确定网格范围（覆盖训练数据并向外扩展1个单位）
x_min, x_max = np.min(x_train[:, 0]) - 1, np.max(x_train[:, 0]) + 1
y_min, y_max = np.min(x_train[:, 1]) - 1, np.max(x_train[:, 1]) + 1
# 生成网格点
xx, yy = np.meshgrid(np.arange(x_min, x_max, step), np.arange(y_min, y_max, step))
# 转换为模型可预测的格式（n行2列）
grid_data = np.concatenate([xx.reshape(-1, 1), yy.reshape(-1, 1)], axis=1)

# KNN分类与不同k值效果对比
# 测试3个常见k值（1、3、10），观察k对分类边界的影响
ks = [1, 3, 10]
# 定义浅色分类背景（对应两类）
cmap_light = ListedColormap(['royalblue', 'lightcoral'])

# 创建子图（1行3列）
fig, axes = plt.subplots(1, 3, figsize=(18, 5))
print(f"\n正在使用k={ks}训练KNN模型...")

for i, k in enumerate(ks):
    # 初始化KNN分类器（默认使用欧氏距离）
    knn = KNeighborsClassifier(n_neighbors=k)
    # 训练模型
    knn.fit(x_train, y_train)
    # 预测网格点类别（用于绘制边界）
    z = knn.predict(grid_data)
    z = z.reshape(xx.shape)  # 转换为网格形状

    # 绘制分类背景
    axes[i].pcolormesh(xx, yy, z, cmap=cmap_light, alpha=0.7)
    # 叠加原始训练数据
    axes[i].scatter(x_train[y_train == 0, 0], x_train[y_train == 0, 1], c='blue', marker='o', alpha=0.8, label='类别0')
    axes[i].scatter(x_train[y_train == 1, 0], x_train[y_train == 1, 1], c='red', marker='x', alpha=0.8, label='类别1')
    # 设置子图信息
    axes[i].set_xlabel('特征1（X轴）')
    axes[i].set_ylabel('特征2（Y轴）')
    axes[i].set_title(f'KNN分类结果（k={k}）')
    axes[i].legend()
    axes[i].grid(alpha=0.3)

plt.tight_layout()
plt.show()

# 输出模型在训练集上的准确率
print("\n各k值对应的训练集准确率：")
for k in ks:
    knn = KNeighborsClassifier(n_neighbors=k)
    knn.fit(x_train, y_train)
    accuracy = knn.score(x_train, y_train)
    print(f"k={k}时，训练集准确率：{accuracy:.4f}")